#include "code_syntaxhighlight.h"

CodeSyntaxHighLight::CodeSyntaxHighLight(QTextDocument* parent)
    : QSyntaxHighlighter(parent)
{
    this->initRules();
}

void CodeSyntaxHighLight::highlightBlock(const QString& text)
{
    for (auto& rule : _rules) {
        QRegularExpressionMatchIterator matchItr = rule.pattern.globalMatch(text);
        while (matchItr.hasNext()) {
            QRegularExpressionMatch expressionMatch = matchItr.next();
            setFormat(expressionMatch.capturedStart(), expressionMatch.capturedLength(), rule.format);
        }
    }
    this->matchMultiLineComment(text);
}

void CodeSyntaxHighLight::initRules()
{
    // 关键字匹配
    this->initKeywordsRule();
    // 类匹配
    this->initClassRule();
    // 数字匹配
    this->initNumberRule();
    // 函数匹配
    this->initFunctionRule();
    // 字符串匹配
    this->initQuotationRule();
    // 单行注释匹配
    this->initSingleLineCommentRule();
    // 多行注释匹配
    this->initMultiLineCommentRule();
}

void CodeSyntaxHighLight::initKeywordsRule()
{
    _keywordFormat.setForeground(Qt::darkBlue);
    _keywordFormat.setFontWeight(QFont::Bold);
    _keywordFormat.setFontFamilies({"Consolas"});
    const QString keyWords[] = {"char", "class", "const",
                                "double", "enum", "explicit",
                                "friend", "inline", "int",
                                "long", "namespace", "operator",
                                "private", "protected", "public",
                                "short", "signals", "signed",
                                "slots", "static", "struct",
                                "template", "typedef", "typename",
                                "union", "unsigned", "virtual",
                                "void", "volatile", "bool"};
    for (const QString& keyword : keyWords) {
        _HightRule rule;
        rule.format = _keywordFormat;
        // \b表示单词的边界
        rule.pattern = QRegularExpression("\\b" + keyword + "\\b");
        _rules << rule;
    }
}

void CodeSyntaxHighLight::initClassRule()
{
    _HightRule classRule;
    _classFormat.setForeground(Qt::darkMagenta);
    _classFormat.setFontWeight(QFont::Bold);
    _classFormat.setFontFamilies({"Consolas"});
    classRule.format = _classFormat;
    classRule.pattern = QRegularExpression("\\bQ[a-zA-Z]+\\b");
    _rules << classRule;
}

void CodeSyntaxHighLight::initNumberRule()
{
    _HightRule numberRule;
    _numberFormat.setForeground(QColor(255, 147, 13));
    numberRule.format = _numberFormat;
    numberRule.pattern = QRegularExpression("[+-]?\\d+\\.?\\d*");
    _rules << numberRule;
}

void CodeSyntaxHighLight::initFunctionRule()
{
    _HightRule functionRule;
    _functionFormat.setFontItalic(true);
    _functionFormat.setForeground(Qt::blue);
    _functionFormat.setFontFamilies({"Consolas"});
    functionRule.format = _functionFormat;
    functionRule.pattern = QRegularExpression("\\b[0-9a-zA-Z_]+(?=\\()");
    _rules << functionRule;
}

void CodeSyntaxHighLight::initQuotationRule()
{
    _HightRule stringRule;
    _quotationFormat.setForeground(Qt::darkGreen);
    _quotationFormat.setFontFamilies({"Consolas"});
    stringRule.format = _quotationFormat;
    stringRule.pattern = QRegularExpression("\".*\"");
    _rules << stringRule;
}

void CodeSyntaxHighLight::initSingleLineCommentRule()
{
    _HightRule commentRule;
    _singleLineCommentFormat.setForeground(Qt::darkGreen);
    _singleLineCommentFormat.setFontFamilies({"Consolas"});
    commentRule.format = _singleLineCommentFormat;
    commentRule.pattern = QRegularExpression("//[^\\n]*");
    _rules << commentRule;
}

void CodeSyntaxHighLight::initMultiLineCommentRule()
{
    _multiLineCommentFormat.setForeground(Qt::darkGreen);
    _multiLineCommentFormat.setFontFamilies({"Consolas"});
    _multiStartExp.setPattern("/\\*");
    _multiEndExp.setPattern("\\*/");
}

void CodeSyntaxHighLight::matchMultiLineComment(const QString& text)
{
    // 0表示不在多行注释内 1表示在多行注释内
    setCurrentBlockState(0);
    int startIndex;
    if (previousBlockState() == 1) {
        startIndex = 0;
    } else {
        // 如果没有找到 /* 返回-1
        startIndex = text.indexOf(_multiStartExp);
    }
    // 开始寻找 */
    while (startIndex >= 0) {
        QRegularExpressionMatch match = _multiEndExp.match(text, startIndex);
        int endIndex = match.capturedStart();
        int commentLength = 0;
        if (endIndex == -1) {
            // 当前行没有找到 */
            setCurrentBlockState(1);
            commentLength = text.length() - startIndex;
        } else {
            // 当前行有找到 */
            commentLength = endIndex - startIndex + match.capturedLength();
        }
        setFormat(startIndex, commentLength, _multiLineCommentFormat);
        // 继续在当前行中寻找 /*
        startIndex = text.indexOf(_multiStartExp, startIndex + commentLength);
    }
}


